package com.lixixi.tingshu.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.lixixi.tingshu.account.api.AccountApiFeignClient;
import com.lixixi.tingshu.album.api.AlbumApiFeignClient;
import com.lixixi.tingshu.common.constant.KafkaConstant;
import com.lixixi.tingshu.common.constant.RedisConstant;
import com.lixixi.tingshu.common.constant.SystemConstant;
import com.lixixi.tingshu.common.result.Result;
import com.lixixi.tingshu.common.result.ResultCodeEnum;
import com.lixixi.tingshu.common.util.AuthContextHolder;
import com.lixixi.tingshu.exception.BaseException;
import com.lixixi.tingshu.model.album.AlbumInfo;
import com.lixixi.tingshu.model.album.TrackInfo;
import com.lixixi.tingshu.model.order.OrderDerate;
import com.lixixi.tingshu.model.order.OrderDetail;
import com.lixixi.tingshu.model.order.OrderInfo;
import com.lixixi.tingshu.model.user.VipServiceConfig;
import com.lixixi.tingshu.order.helper.SignHelper;
import com.lixixi.tingshu.order.service.OrderDerateService;
import com.lixixi.tingshu.order.service.OrderDetailService;
import com.lixixi.tingshu.order.service.OrderInfoService;
import com.lixixi.tingshu.order.service.TradeService;
import com.lixixi.tingshu.user.api.UserApiFeignClient;
import com.lixixi.tingshu.vo.account.AccountLockVo;
import com.lixixi.tingshu.vo.order.OrderDerateVo;
import com.lixixi.tingshu.vo.order.OrderDetailVo;
import com.lixixi.tingshu.vo.order.OrderInfoVo;
import com.lixixi.tingshu.vo.order.TradeVo;
import com.lixixi.tingshu.vo.user.UserInfoVo;
import com.lixixi.tingshu.vo.user.UserPaidRecordVo;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class TradeServiceImpl implements TradeService {
	@Autowired
	RedisTemplate<String, String> redisTemplate;

	@Autowired
	OrderInfoService orderInfoService;

	@Autowired
	RedissonClient redissonClient;

	@Autowired
	OrderDetailService orderDetailService;

	@Autowired
	OrderDerateService orderDerateService;

	@Autowired
	UserApiFeignClient userApiFeignClient;

	@Autowired
	AlbumApiFeignClient albumApiFeignClient;

	@Autowired
	AccountApiFeignClient accountApiFeignClient;
	@Autowired
	private KafkaTemplate<Object, String> kafkaTemplate;

	@Override
	public OrderInfoVo tradeDetatil(TradeVo tradeVo) {
		//返回数据
		OrderInfoVo orderInfoVo = new OrderInfoVo();
		//获取用户id
		Long userId = AuthContextHolder.getUserId();
		//获取用户权限
		Boolean isVip = Boolean.FALSE;
		Result<UserInfoVo> userInfoForFeign = userApiFeignClient.getUserInfoForFeign(userId);
		if (userInfoForFeign.getData().getIsVip().equals(SystemConstant.VIP)
				&&
				new Date().before(userInfoForFeign.getData().getVipExpireTime()))
			isVip = Boolean.TRUE;
		//随机生成一个交易号
		String tradeNo = UUID.randomUUID().toString().replaceAll("-", "");
		//使用同步锁将其存入缓存,用户交易最多持续10分钟
		redisTemplate.opsForValue().setIfAbsent(RedisConstant.ORDER_TRADE_NO + tradeNo
				, userId.toString()
				, RedisConstant.CACHE_TEMPORARY_TIMEOUT
				, TimeUnit.SECONDS);
		//付款项目类型: 1001-专辑 1002-声音 1003-vip会员
		//获取项目id
		Long itemId = tradeVo.getItemId();
		//获取付款项目类型
		String itemType = tradeVo.getItemType();
		//判断付款项目类型
		switch (itemType)
		{
			case SystemConstant.ORDER_ITEM_TYPE_ALBUM:
			{//专辑项目
				OrderDetailVo orderDetailVo = new OrderDetailVo();
				OrderDerateVo orderDerateVo = new OrderDerateVo();
				//获取专辑信息
				Result<AlbumInfo> albumInfoResult = albumApiFeignClient.getAlbumInfoById(itemId);
				AlbumInfo albumInfo = albumInfoResult.getData();
				//获取专辑总集数
				Integer includeTrackCount = albumInfo.getIncludeTrackCount();
				//获取专辑折扣
				BigDecimal discount = albumInfo.getDiscount();
				BigDecimal vipDiscount = albumInfo.getVipDiscount();
				if (!discount.equals(BigDecimal.valueOf(-1)))
					orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
				//获取折扣,vip不打折则保持原有价格
				if (isVip && !vipDiscount.equals(BigDecimal.valueOf(-1)))
				{
					discount = vipDiscount;
					orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
				}
				//获取价格
				BigDecimal price = albumInfo.getPrice();
				//计算订单原始金额
				BigDecimal originalAmount = price.multiply(BigDecimal.valueOf(includeTrackCount));
				//订单总金额
				BigDecimal orderAmount = !discount.equals(BigDecimal.valueOf(-1)) ?
						price.multiply(discount.multiply(BigDecimal.valueOf(10)))
								.divide(BigDecimal.valueOf(10)) :
						originalAmount;
				//减免总金额
				BigDecimal derateAmount = orderAmount.subtract(orderAmount);
				//设置订单金额
				orderInfoVo.setOrderAmount(orderAmount);
				orderInfoVo.setDerateAmount(derateAmount);
				orderInfoVo.setOriginalAmount(originalAmount);
				//填充订单减免列表
				orderDerateVo.setDerateAmount(derateAmount);
				orderInfoVo.setOrderDerateVoList(List.of(orderDerateVo));
				//填充订单明细列表
				orderDetailVo.setItemId(itemId);
				orderDetailVo.setItemName(albumInfo.getAlbumTitle());
				orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
				orderDetailVo.setItemPrice(price);
				orderInfoVo.setOrderDetailVoList(List.of(orderDetailVo));
				break;
			}
			case SystemConstant.ORDER_ITEM_TYPE_TRACK:
			{//声音项目
				//声音购买不打折
				//获取声音购买数量
				Integer trackCount = tradeVo.getTrackCount();
				//获取指定声音详情列表
				Result<List<TrackInfo>> orderTrackInfosResult = albumApiFeignClient.getOrderTrackInfoList(itemId, trackCount);
				List<TrackInfo> trackInfos = orderTrackInfosResult.getData();
				//查询专辑
				Result<AlbumInfo> albumInfoResult = albumApiFeignClient.getAlbumInfoById(trackInfos.get(0).getAlbumId());
				AlbumInfo albumInfo = albumInfoResult.getData();
				//获取声音价格
				BigDecimal price = albumInfo.getPrice();
				//获取购买的声音数量
				int size = trackInfos.size();
				//计算订单金额
				BigDecimal originalAmount = price.multiply(BigDecimal.valueOf(size));
				BigDecimal derateAmount = BigDecimal.valueOf(0);
				BigDecimal orderAmount = originalAmount;
				//设置订单金额
				orderInfoVo.setOrderAmount(orderAmount);
				orderInfoVo.setDerateAmount(derateAmount);
				orderInfoVo.setOriginalAmount(originalAmount);
				//填充订单明细
				LinkedList<OrderDetailVo> orderDetailVos = new LinkedList<>();
				LinkedList<OrderDerateVo> orderDerateVos = new LinkedList<>();
				if (trackInfos != null)
				{
					for (TrackInfo trackInfo : trackInfos)
					{
						//填充订单减免列表
						OrderDerateVo orderDerateVo = new OrderDerateVo();
						orderDerateVo.setDerateAmount(derateAmount);
						orderDerateVos.add(orderDerateVo);
						//填充订单明细列表
						OrderDetailVo orderDetailVo = new OrderDetailVo();
						orderDetailVo.setItemId(trackInfo.getId());
						orderDetailVo.setItemName(albumInfo.getAlbumTitle());
						orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
						orderDetailVo.setItemPrice(price);
						orderDetailVos.add(orderDetailVo);
					}
				}
				orderInfoVo.setOrderDerateVoList(orderDerateVos);
				orderInfoVo.setOrderDetailVoList(orderDetailVos);
				orderInfoVo.setOrderDerateVoList(List.of());
				break;
			}
			case SystemConstant.ORDER_ITEM_TYPE_VIP:
			{//vip服务
				OrderDetailVo orderDetailVo = new OrderDetailVo();
				OrderDerateVo orderDerateVo = new OrderDerateVo();
				//获取vip详情
				Result<VipServiceConfig> serviceConfigResult = userApiFeignClient.findVipServiceById(itemId);
				VipServiceConfig vipServiceConfig = serviceConfigResult.getData();
				//获取原价
				BigDecimal originalAmount = vipServiceConfig.getPrice();
				//获取折后价格
				BigDecimal orderAmount = vipServiceConfig.getDiscountPrice();
				//获取减免价格
				BigDecimal derateAmount = originalAmount.subtract(orderAmount);
				orderInfoVo.setOriginalAmount(originalAmount);
				orderInfoVo.setOrderAmount(orderAmount);
				orderInfoVo.setDerateAmount(derateAmount);
				//填充订单减免列表
				orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
				orderDerateVo.setDerateAmount(derateAmount);
				orderInfoVo.setOrderDerateVoList(List.of(orderDerateVo));
				//填充订单明细列表
				orderDetailVo.setItemId(itemId);
				orderDetailVo.setItemName(vipServiceConfig.getName());
				orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
				orderDetailVo.setItemPrice(vipServiceConfig.getPrice());
				orderInfoVo.setOrderDetailVoList(List.of(orderDetailVo));
				break;
			}
			default:
				throw new BaseException(ResultCodeEnum.PAY_ITEM_ERROR);
		}
		//填充其余信息
		orderInfoVo.setTradeNo(tradeNo);
		//todo:默认初始化支付方式为wx
		orderInfoVo.setPayWay(SystemConstant.ORDER_PAY_WAY_WEIXIN);
		orderInfoVo.setItemType(itemType);
		orderInfoVo.setTimestamp(new Date().getTime() + 500000);
		TreeMap treeMap = JSONObject.parseObject(JSONObject.toJSONString(orderInfoVo), TreeMap.class);
		//生成校验签名
		orderInfoVo.setSign(SignHelper.getSign(treeMap));
		return orderInfoVo;
	}

	@Override
	@Transactional
	public Map<String, Object> submitOrder(OrderInfoVo orderInfoVo) {
		//获取用户id
		Long userId = AuthContextHolder.getUserId();
		//获取支付类型
		String payWay = orderInfoVo.getPayWay();
		//校验订单签名
		SignHelper.checkSign(JSONObject.parseObject(JSONObject.toJSONString(orderInfoVo), Map.class));
		//校验订单号
		//编写lua脚本实现交易号校验原子性
		String luaScriptOrderNo = "if redis.call('exist', KEY[1])\n" +
				"then\n" +
				"	return redis.call('del', KEY[1])\n" +
				"else\n" +
				"	return 0\n" +
				"end";
		Long execute = redisTemplate.execute(new DefaultRedisScript<>(luaScriptOrderNo, Long.class)
				, List.of(RedisConstant.ORDER_TRADE_NO + orderInfoVo.getTradeNo()));
		if (execute == 0)
		{
			//脚本返回0则说明订单重复提交
			throw new BaseException(ResultCodeEnum.ORDER_SUBMIT_REPEAT);
		}
		//重新生成订单号
		String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
		//判断支付类型
		switch (payWay)
		{
			case SystemConstant.ORDER_PAY_WAY_ACCOUNT:
			{//余额支付
				try
				{
					//保存订单
					saveOrder(orderInfoVo, userId, orderNo);
					//构建锁定金额对象
					AccountLockVo accountLockVo = new AccountLockVo();
					accountLockVo.setAmount(orderInfoVo.getOrderAmount());
					accountLockVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
					accountLockVo.setUserId(userId);
					accountLockVo.setOrderNo(orderNo);
					//检查并锁定金额
					Result result = accountApiFeignClient.checkAndLock(accountLockVo);
					//订单锁定不成功, 抛出异常
					if (!ResultCodeEnum.SUCCESS.getCode().equals(result))
					{
						throw new BaseException(result.getCode(), result.getMessage());
					}
					try
					{
						//发送扣减金额消息
						kafkaTemplate.send(KafkaConstant.QUEUE_ACCOUNT_MINUS, orderNo);
					} catch (BaseException e)
					{
						//扣减金额发送失败, 主动解锁金额
						kafkaTemplate.send(KafkaConstant.QUEUE_ACCOUNT_UNLOCK, JSONObject.toJSONString(accountLockVo));
						throw e;
					}
					//构建商品记录信息
					UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
					userPaidRecordVo.setUserId(userId);
					userPaidRecordVo.setItemType(orderInfoVo.getItemType());
					userPaidRecordVo.setOrderNo(orderNo);
					//获取订单明细的商品id列表
					List<Long> list = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).toList();
					userPaidRecordVo.setItemIdList(list);
					//发送消息,将商品添加至用户持有商品
					kafkaTemplate.send(KafkaConstant.QUEUE_USER_PAY_RECORD, JSONObject.toJSONString(userPaidRecordVo));
					//更新支付状态
					orderInfoService.update(new LambdaUpdateWrapper<OrderInfo>()
							.eq(OrderInfo::getOrderNo, orderNo)
							.set(OrderInfo::getOrderStatusName, "已支付")
							.set(OrderInfo::getOrderStatus, SystemConstant.ORDER_STATUS_PAID));
				} catch (BaseException e)
				{

					throw new BaseException(ResultCodeEnum.ORDER_SAVE_ERROR);
				}
				break;
			}
			case SystemConstant.ORDER_PAY_WAY_WEIXIN:
			{//微信支付
				OrderInfo orderInfo = saveOrder(orderInfoVo, userId, orderNo);
				//发送消息,监听订单超时
				RBlockingDeque<String> deque = redissonClient.getBlockingDeque(RedisConstant.ORDER_DELAY_QUEUE);
				RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(deque);
				//发送延迟消息,设定5分钟后订单超时自动检测订单状态
				delayedQueue.offer(String.valueOf(orderInfo.getId()), 5, TimeUnit.SECONDS);
				//todo:wx支付逻辑
				break;
			}
			case SystemConstant.ORDER_PAY_WAY_ALIPAY:
			{//阿里支付
				break;
			}
			default:
				throw new BaseException(ResultCodeEnum.ILLEGAL_REQUEST);
		}
		HashMap<String, Object> map = new HashMap<>();
		map.put("orderNo", orderNo);
		return map;
	}

	@Override
	public OrderInfo saveOrder(OrderInfoVo orderInfoVo, Long userId, String orderNo) {
		OrderInfo orderInfo = new OrderInfo();
		//获取支付方式名称
		String payWay = orderInfoVo.getPayWay();
		String payWayName = getPayWayName(payWay);
		BeanUtil.copyProperties(orderInfoVo, orderInfo);
		//填充属性
		orderInfo.setUserId(userId);
		orderInfo.setOrderNo(orderNo);
		orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
		orderInfo.setPayWayName(payWayName);
		orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
		orderInfo.setOrderStatusName("未支付");
		//保存订单
		orderInfoService.save(orderInfo);
		//保存订单明细
		List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
		if (!orderDetailVoList.isEmpty())
		{
			List<OrderDetail> orderDetails = orderDetailVoList.stream().map(orderDetailVo -> {
				OrderDetail orderDetail = BeanUtil.toBean(orderDetailVo, OrderDetail.class);
				orderDetail.setOrderId(orderInfo.getId());
				return orderDetail;
			}).toList();
			orderDetailService.saveBatch(orderDetails);
		}
		//保存订单减免
		List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
		if (!orderDetailVoList.isEmpty())
		{
			List<OrderDerate> orderDerates = orderDerateVoList.stream().map(orderDerateVo -> {
				OrderDerate orderDerate = BeanUtil.toBean(orderDerateVo, OrderDerate.class);
				orderDerate.setOrderId(orderInfo.getId());
				return orderDerate;
			}).toList();
			orderDerateService.saveBatch(orderDerates);
		}
		return orderInfo;
	}

	private static String getPayWayName(String payWay) {
		String payWayName;
		if (SystemConstant.ORDER_PAY_WAY_WEIXIN.equals(payWay))
			payWayName = "微信支付";
		else if (SystemConstant.ORDER_PAY_WAY_ALIPAY.equals(payWay))
			payWayName = "支付宝";
		else
			payWayName = "余额支付";
		return payWayName;
	}


}
